using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Web.Hosting;

namespace Thinxoft.HttpLib
{
	/// <summary>
	/// Summary description for Parser.
	/// </summary>
	public class Parser {
		StringBuilder code,xmlList;		
		char[] text;
		private XmlNode directives;
		HttpResource resource;

		

		public Parser(HttpResource resource)
		{
			//initialize code
			code = new StringBuilder();
			xmlList = new StringBuilder();
			bool inCode = false;
			bool header = false;
			this.resource = resource;
			


			//read file
            string file = File.ReadAllText(resource.LocalPath);
            text = file.ToCharArray();
			
			
			

			for(int i = 0; i < text.Length; i++)
			{
				if(text[i] == '<' && text[i+1] == '%' && text[i+2] == '@' && text[i+3] == '[')
				{
					header = true;
					i+=3;

				}
				else
				{
					header = false;
					if(text[i] == '<' && text[i+1] == '%')
					{
						inCode = true;

						//bump index to next character after token <%
						i++;
						i++;
					}
					else
					{
						if(inCode)
						{
							inCode = false;
							i++;
							i++;
						}
					}
				}
				if(header)
				{
					i = LoadHeader(i);
				}
				else
				{
					if(inCode)
					{
						i = LoadCode(i);		
					}
					else
					{
						i = LoadXml(i);
					}
				}

				
			}	
		}

		public int LoadHeader(int index){
		
				StringBuilder xml = new StringBuilder();
				index++; //move index forward one to begin reading
				for(int i = index; i < text.Length; i++){
					if(text[i] == ']' && text[i+1] == '%' && text[i+2] == '>'){
						XmlDocument xdoc = new XmlDocument();
						xdoc.LoadXml(xml.ToString());
						this.directives = xdoc.DocumentElement;
						return i+=2;  //decrement for return
					}
					//add anything but newlines
					if(text[i] != '\n' && text[i] != '\r' && text[i] != '\f' && text[i] >= 13) {
						xml.Append(text[i]);
					}
				}
				throw new Exception("invalid syntax ");
			
		}

		/// <summary>
		/// load code
		/// </summary>
		/// <param name="index"></param>
		/// <returns></returns>
		public int LoadCode(int index){
			switch(text[index]){
				case '=':{
					StringBuilder taglet = new StringBuilder("Response.Write(");
					index++; //move index forward one to begin reading
					for(int i = index; i < text.Length; i++){
						if(text[i] == '%' && text[i+1] == '>'){
							code.Append(taglet.ToString().Trim() + ");");
							return --i;  //decrement for return
						}
						taglet.Append(text[i]);

					}
					throw new Exception("invalid syntax ");
				}
				default:{
					StringBuilder taglet = new StringBuilder();
					for(int i = index; i < text.Length; i++){
						if(text[i] == '%' && text[i+1] == '>'){
							code.Append(taglet.ToString().Trim());
							return --i;  //decrement for return
						}
						taglet.Append(text[i]);

					}
					throw new Exception("invalid syntax ");
				}
					
			}
			
			
		}

		/// <summary>
		/// load xml information
		/// </summary>
		/// <param name="index"></param>
		/// <returns></returns>
		public int LoadXml(int index){
			StringBuilder xml = new StringBuilder("\n Response.Write(\"");
			for(int i = index; i < text.Length; i++){
				if(text[i] == '<' && text[i+1] == '%'){
					string result = xml.ToString().Trim();
					code.Append(result + "\");");  //
					//xmlList.Append(result);
					return --i;
				}

				//add anything but newlines
				if(text[i] != '\n' && text[i] != '\r' && text[i] != '\f' && text[i] >= 13) {
					if(text[i] == '\"'){
						//xmlList.Append("\\" + text[i]);
						xml.Append("\\" + text[i]);
					}else{
						//xmlList.Append(text[i]);
						xml.Append(text[i]);

					}
				}

			}

			code.Append(xml.ToString().Trim() + "\");");
			return text.Length + 1;
			
		}

		public HttpResource Resource
		{
			get
			{
				return this.resource;
			}
		}

		public string CodeListing{
			get{
				return code.ToString();
			}
		}

		public XspDirectives Directives{
			get{
				if(directives != null){
					return new XspDirectives(this.directives);
				}else{
					return null;
				}
			}
		}
		
	}
}
